package com.liuwei.assemble.controller;

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.liuwei.assemble.common.*;
import com.liuwei.assemble.constants.PathConstants;
import com.liuwei.assemble.dtos.GeneratorContextDTO;
import com.liuwei.assemble.factory.GeneratorFactory;
import com.liuwei.assemble.vo.GeneratorReqVO;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("generator")
//https://blog.csdn.net/yifanSJ/article/details/79073067?utm_source=blogxgwz5
public class GeneratorController {
    private static final Logger logger = LoggerFactory.getLogger(GeneratorController.class);

    @RequestMapping("")
    public Result generator(GeneratorReqVO requestVO) throws Exception {
    	SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
    	//参数验证
        if(StringUtils.isBlank(requestVO.getProjectName())){
            requestVO.setProjectName("demo");
        }
    	String tempPath = PathConstants.GENERATOR_TMP_LIBRARY;
    	String srcDatePath  = "/src" + format.format(new Date());
    	String zipPath = tempPath + "/zip/"+srcDatePath;
    	String zipName = "/zip"+srcDatePath+"/"+requestVO.getProjectName() + ".zip";
    	String rootPath = tempPath+srcDatePath+"/"+requestVO.getProjectName();
    	String mainJavaPath = rootPath+"/src/main/java";
    	String mainResourcesPath = rootPath+"/src/main/resources";
    	
    	//DB连接配置
        DataSourceConfig dataSourceConfig=new DataSourceConfig();
        dataSourceConfig.setDbType(requestVO.getDbType());
        dataSourceConfig.setDriverName(requestVO.getDriverNameFromType());
        dataSourceConfig.setUsername(requestVO.getUsername());
        dataSourceConfig.setPassword(requestVO.getPassword());
        dataSourceConfig.setUrl(requestVO.getConnectionUrl());
        
        // 配置包名
        PackageConfig packageConfig=new PackageConfig();
        packageConfig.setParent(requestVO.getParent());
        //packageConfig.setModuleName(requestVO.getParent());
        packageConfig.setEntity(requestVO.getEntity());
        packageConfig.setMapper(requestVO.getMapper());
        packageConfig.setXml(requestVO.getXml());
        packageConfig.setService(requestVO.getService());
        packageConfig.setServiceImpl(requestVO.getServiceImpl());
        packageConfig.setController(requestVO.getController());
        logger.error("step1:webtype:{}",requestVO.getWebType());
        
        // 配置保存路径
        GlobalConfig globalConfig=new GlobalConfig();
        globalConfig.setOutputDir(mainJavaPath);
        globalConfig.setFileOverride(false);
        globalConfig.setBaseColumnList(true);
        globalConfig.setBaseResultMap(true);
        globalConfig.setOpen(false);
        globalConfig.setAuthor(requestVO.getAuthor());
        globalConfig.setEnableCache(false);
        globalConfig.setSwagger2(true);
        globalConfig.setDateType(DateType.ONLY_DATE);
        // 默认service接口名IXXXService
        globalConfig.setServiceName("%sService");

        AutoGenerator autoGenerator = new AutoGenerator();
        autoGenerator.setDataSource(dataSourceConfig);
        autoGenerator.setPackageInfo(packageConfig);
        autoGenerator.setGlobalConfig(globalConfig);

        //配置生成策略
        StrategyConfig strategy=new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        if(!ArrayUtils.isEmpty(requestVO.getTableNames())){
            strategy.setInclude(requestVO.getTableNames());
        }
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setSuperControllerClass("com.lixiang.framework.oauth.OauthBaseController");

        strategy.setSuperMapperClass("com.lixiang.factory.wcs.dispatcher.biz.common.repository.support.mapper.BaseOptimisticLockerDeleteVersionMapper");

        strategy.setEntityLombokModel(true);
        strategy.setEntitySerialVersionUID(true);
        strategy.setSuperEntityClass("com.lixiang.factory.wcs.dispatcher.biz.common.repository.support.entity.BaseOptimisticLockerDeleteVersionEntity");
        strategy.setSuperEntityColumns(new String[]{"id","version","deleted","deleted_version","create_time","create_by_id","create_by_name","update_time","update_by_id","update_by_name",});
        autoGenerator.setStrategy(strategy);

        TemplateConfig tc = new TemplateConfig();
        // 自定义 controller 模板
        tc.setController("/velocity/springboot/java/controller/controller.java.vm");
        autoGenerator.setTemplate(tc);

        // 注入自定义配置，可以在 VM 中使用 cfg.abc 【可无】
        InjectionConfig inject = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("basePackage", requestVO.getParent());
                this.setMap(map);
            }
        };
        autoGenerator.setCfg(inject);
        // 5.执行，关闭生成器
        autoGenerator.execute();
        
        //项目其他文件生成
        List<TableInfo>  tableInfos = autoGenerator.getConfig().getTableInfoList();
        GeneratorContextDTO genContext = new GeneratorContextDTO();
        genContext.setTableInfos(tableInfos);
        genContext.setProjectName(requestVO.getProjectName());
        genContext.setRootPath(rootPath);
        genContext.setJavaPath(mainJavaPath);
        genContext.setResourcePath(mainResourcesPath);
        genContext.setAuthor(requestVO.getAuthor());
        genContext.setDriverClassName(requestVO.getDriverNameFromType());
        genContext.setPackageConfig(packageConfig);
        genContext.setGlobalConfig(globalConfig);
        genContext.setDataSourceConfig(dataSourceConfig);
        genContext.setIdGenerator(requestVO.getIdGenerator());
        genContext.setRequestVO(requestVO);
        //生成springboot配置代码
        GeneratorFactory.generator(requestVO.getProjectType(),genContext);
        logger.error("step1:webtype2:{}",requestVO.getWebType());

        //生成boostrap前端代码
        //GeneratorFactory.generator(requestVO.getWebType(),genContext);
        //logger.error("file:{}",rootPath);

        /** 打包操作*/
        GIOUtils.fileToZip(rootPath, zipPath, requestVO.getProjectName());
        removeTempDirectory(tempPath,srcDatePath,requestVO.getProjectName());

        //文件下载实现
        return Result.success(zipName);
    }

    private void checkDbConnection(GeneratorReqVO requestVO) throws SQLException {
        String url = StringHelper.format("jdbc:mysql://{}:{}/{}",requestVO.getConnectionUrl(),requestVO.getPort(),requestVO.getDatabaseName()) ;
        String user = requestVO.getUsername();
        String password = requestVO.getPassword();
        Connection connection = DriverManager.getConnection(url, user, password);
    }
    
    /** 执行完毕后删除冗余文件*/
    private void removeTempDirectory(final String tempPath,final String srcPath,final String projectName) {
        new Thread(new Runnable() { 
        @Override
        public void run() {
            try {
                Thread.sleep(120000);
                File dirFile = new File(tempPath + srcPath);
                File zipFile = new File(tempPath + "/tmp" + "/" + srcPath+"/"+projectName +".zip");
                GIOUtils.deleteDir(dirFile);
                GIOUtils.deleteDir(zipFile);
                dirFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
        }).start();
    }



    @RequestMapping(value="/download", method = RequestMethod.GET)
    public void downloadFile(HttpServletResponse response, String url) throws IOException {

        File file = new File(PathConstants.GENERATOR_TMP_LIBRARY+"/"+url);
        if(!file.exists()){
            String errorMessage = "Sorry. The file you are looking for does not exist";
            System.out.println(errorMessage);
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(errorMessage.getBytes(Charset.forName("UTF-8")));
            outputStream.close();
            return;
        }

        String mimeType= URLConnection.guessContentTypeFromName(file.getName());
        if(mimeType==null){
            System.out.println("mimetype is not detectable, will take default");
            mimeType = "application/octet-stream";
        }

        System.out.println("mimetype : "+mimeType);

        response.setContentType(mimeType);

        /* "Content-Disposition : inline" will show viewable types [like images/text/pdf/anything viewable by browser] right on browser
            while others(zip e.g) will be directly downloaded [may provide save as popup, based on your browser setting.]*/
        response.setHeader("Content-Disposition", String.format("inline; filename=\"" + file.getName() +"\""));


        /* "Content-Disposition : attachment" will be directly download, may provide save as popup, based on your browser setting*/
        //response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getName()));

        response.setContentLength((int)file.length());

        InputStream inputStream = new BufferedInputStream(new FileInputStream(file));

        //Copy bytes from source to destination(outputstream in this example), closes both streams.
        FileCopyUtils.copy(inputStream, response.getOutputStream());
    }
}
